#include "drv_rs485.h"
#include "drv_timer.h"
#include "drv_rtc.h"
#include "base_func.h"
// #include "drv_upgrade.h"
#include "wifi.h"

#define TAG "drv_rs485"

vdata_sem_t rs485_sem;
int fd_rs485, fd_tuya;

uint8_t g_Timer8DispCommErrCnt = 0;
uint16_t g_sys_error_count = 0;

static int  mach_rx_buff_length = 0;
static uint8_t s_comm_tx_step = 0, s_tx_count = 0, s_Minute = 0;
static uint8_t word100_init[100] = {0}, word200_init[100] = {0};

static uint8_t g_DispCommHasInitBit = 0;
static uint8_t g_UartDispTxBuf[150];
static uint16_t module_word_reg[REG_MAX_NUM];
static uint8_t rs485_buff[1024];
static uint8_t uart0_buff[200];


int uart_write_bytes(int uart_num, const void *src, size_t size)
{
    switch (uart_num)
    {
        case 0: 
            write_data(fd_tuya, (void *)src, size); 
            break;
        case 1:
            write_data(fd_rs485, (void *)src, size);
            break;
    }
}

uint16_t *find_addr_index(int devAddr, int regAddr)
{
    static uint16_t temp_value = 0;
    if(regAddr >= REG_MAX_NUM){
        return &temp_value;
    }

    return &module_word_reg[regAddr];
}

uint8_t *find_modbus_index(int addr)
{

    uint8_t function = (addr >> 16) & 0xF;
    // uint16_t devAddr = (addr >> 12) & 0xF;
    uint16_t regAddr = addr & 0x0FFF;

    switch (function)
    {
        case 1:
            break;

        case 2:
            break;

        case 3:
            if(regAddr >= REG_MAX_NUM){
                return NULL;
            }
            return (uint8_t *)&module_word_reg[regAddr];

        case 4:
            break;
        
        default:
            break;
    }

    return NULL;
}


int fun_insert_data_to_cache(int dev_id, int funcode, int start_addr, int reg_num, uint8_t *data)
{
    bit_word tmp_BitWord ;
    int i = 0, j = 0, num = reg_num, count = 0;
    switch(funcode){
        case 0x13:
            if(start_addr <= REG_MAX_NUM){
                // ESP_LOGI(TAG,"start_addr -> [%d] [%d]...\r\n", start_addr, reg_num);
                if((start_addr + reg_num) > REG_MAX_NUM){
                    num = REG_MAX_NUM - start_addr;
                }
                for(i = 0; i < num; i++){//WORD 个数
                    module_word_reg[start_addr + i] = ((uint16_t)data[i*2] << 8) + (uint8_t)data[i*2 + 1];
                    switch (start_addr + i)
                    {
                        case 606:g_UserSet.temp_env = module_word_reg[start_addr + i];break;
                        case 610:g_UserSet.temp_tank = module_word_reg[start_addr + i];break;
                    }
                    if ((start_addr + i) == 20){
                        g_DispCommHasInitBit |= 0x01;
                        s_comm_tx_step = 1;
                    }
                    if(g_DispCommHasInitBit & 0x01){
                        if(((start_addr + i) >= 100) && ((start_addr + i) < 200)){
                            word100_init[start_addr + i - 100] = 1;
                        }
                        if(((start_addr + i) >= 200) && ((start_addr + i) < 300)){
                            word200_init[start_addr + i - 200] = 1;
                        }
                        if((g_DispCommHasInitBit & 0x02) == 0){
                            count = 0;
                            for(j = 0; j < 100; j++){
                                count += word100_init[j];
                            }
                            if((count >= module_word_reg[18]) || (count >= 100)){
                                g_DispCommHasInitBit |= 0x02;
                                s_comm_tx_step = 2;
                            }
                        }
                        if((g_DispCommHasInitBit & 0x04) == 0){
                            count = 0;
                            for(j = 0; j < 100; j++){
                                count += word200_init[j];
                            }
                            if((count >= module_word_reg[18]) || (count >= 100)){
                                g_DispCommHasInitBit |= 0x04;
                                s_comm_tx_step = 3;
                            }
                        }
                    }
                }
            }

            if(g_UserSet.Mode == 0){
                g_UserSet.Mode_Auto  = (module_word_reg[600] & (1 << 5)) ? 1 : 0;
            }else{
                g_UserSet.Mode_Auto = g_UserSet.Mode - 1;
            }

            g_UserSet.ErrorCode = module_word_reg[609];
            if(g_UserSet.Updata2CommCnt || g_UserSet.PrjSetFlag || (g_UserSet.TimerPwrOn < 3)){
                break;
            }
            g_UserSet.f_On  = (module_word_reg[600] & (1 << 4)) ? 1 : 0;
            g_UserSet.Mode = (module_word_reg[600] & 0x0F);

            g_UserSet.temp_return = module_word_reg[610];
            g_UserSet.SetTemp[USER_SET_MODE_WATER] = module_word_reg[605];

            g_UserSet.SysID = module_word_reg[4];

            g_UserSet.SetTempMin[USER_SET_MODE_WATER] = module_word_reg[17];
            g_UserSet.SetTempMax[USER_SET_MODE_WATER] = module_word_reg[16];

            tmp_BitWord.word = module_word_reg[607];
            g_UserSet.f_DF = tmp_BitWord.bit.b0;
            g_UserSet.f_Recycle = tmp_BitWord.bit.b2;
            g_UserSet.f_Quick = tmp_BitWord.bit.b4;
            g_UserSet.f_Disinfection = tmp_BitWord.bit.b6;
            // g_UserSet.f_Pump = tmp_BitWord.bit.b8;
            g_UserSet.f_Heater = tmp_BitWord.bit.b10;

            tmp_BitWord.word = module_word_reg[608];
            g_UserSet.f_CoolProtect = tmp_BitWord.bit.b0;
            g_UserSet.f_Solar = tmp_BitWord.bit.b4;
            g_UserSet.f_Holiday = tmp_BitWord.bit.b6;
            g_UserSet.f_Quiet = tmp_BitWord.bit.b13*2 + tmp_BitWord.bit.b12;
            g_UserSet.f_ECO = tmp_BitWord.bit.b15*2 + tmp_BitWord.bit.b14;

            tmp_BitWord.word = module_word_reg[613];
            g_UserSet.f_ysj = (tmp_BitWord.bit.b15 * 2 + tmp_BitWord.bit.b14) ? 1 : 0;
            g_UserSet.f_Pump = (tmp_BitWord.bit.b8 * 2 + tmp_BitWord.bit.b9) ? 1 : 0;
            break;
    }
    return 0;
}

int protocol_stack_parse(int index, uint8_t *raw_data, int len)
{
    uint8_t* data = NULL, frame_count = 0;
    uint16_t check_sum = 0, calc_sum = 0, length = len, data_len = 0;
    static uint8_t mach_rx_buff[500];

    if(length >= 2000){
        return 0;
    }
    memcpy(&mach_rx_buff[mach_rx_buff_length], raw_data, length);
    mach_rx_buff_length += length;
    // printf("mach_rx_buff_length -> [%d]...\r\n", mach_rx_buff_length);

    for (data = mach_rx_buff; data < (mach_rx_buff + mach_rx_buff_length); data++){
        if (data[0] == 0x7E) {
            data_len = data[6]*2 + 9;
            //数据缓冲区数据不够帧解析，剩余数据挪到最前面，和后面接收的数据进行拼接
            if((data + data_len) > (mach_rx_buff + mach_rx_buff_length)){
                mach_rx_buff_length = (mach_rx_buff + mach_rx_buff_length - data);
                memcpy(mach_rx_buff, data, mach_rx_buff_length);
                // printf("frame_count -> [%d]...\r\n", frame_count);
                return frame_count;
            }
            calc_sum = crc16(data, data_len - 2);
            check_sum = (data[data_len - 2] << 8) + data[data_len - 1];
            //数据量足够时，计算CRC校验是否正确，不正确就跳过
            if (calc_sum != check_sum) {
                continue;
            }

            // printf("crc ok! -> [%02x]...\r\n", data[3]);
            g_UserSet.Test_RX++;
            g_Timer8DispCommErrCnt = 0;
            switch(data[3]){
                case 0x11:
                case 0x13:
                    if((data[2] >= 1)&&(data[2] <= 16)){
                        fun_insert_data_to_cache(data[2], data[3], ((uint16_t)data[4]*256 + (uint8_t)data[5]), data[6], &data[7]);
                    }
                    break;

                case 0x1B:
                    g_UserSet.PrjSetMax = ((uint16_t)data[9]*256 + (uint8_t)data[10]);
                    g_UserSet.PrjSetMin = ((uint16_t)data[11]*256 + (uint8_t)data[12]);
                    g_UserSet.PrjSetType = ((uint16_t)data[13]*256 + (uint8_t)data[14]);
                    printf("g_UserSet.PrjSet -> %d %d %d", g_UserSet.PrjSetMax, g_UserSet.PrjSetMin, g_UserSet.PrjSetType);
                    break;
            }
            frame_count ++;
        }
    }
    mach_rx_buff_length = 0;
    // printf("frame_count -> [%d]...\r\n", frame_count);
    return frame_count;
}

void fun_CommDispTx(void)
{
    int index = 0, reg_count = 0;
    word_def tmp_crc16;
    word_def tmp_dataAddr;
    word_def tmp_dataWord;
    bit_word tmp_BitWord ;
    static int s_Second = 0;

    g_UartDispTxBuf[index++] = 0x7E;
    g_UartDispTxBuf[index++] = 1;
    g_UartDispTxBuf[index++] = 0xF1;
    g_UserSet.Test_TX++;
    if((g_CurrentRTC.Second == 30) && (s_Second != g_CurrentRTC.Second)){
        g_UartDispTxBuf[index++] = 0x10;
        tmp_dataAddr.word = 621;
        g_UartDispTxBuf[index++] = tmp_dataAddr.byte.high;
        g_UartDispTxBuf[index++] = tmp_dataAddr.byte.low;
        g_UartDispTxBuf[index++] = 1;

        tmp_dataAddr.word = (int16_t)(g_UserSet.Test_TEMP * 10);
        g_UartDispTxBuf[index++] = tmp_dataAddr.byte.high;
        g_UartDispTxBuf[index++] = tmp_dataAddr.byte.low;
    }else if (g_UserSet.PrjSetFlag){
        g_UserSet.PrjSetFlag--;

        g_UartDispTxBuf[index++] = 0x10;
        tmp_dataAddr.word = g_UserSet.PrjSetAddr;
        g_UartDispTxBuf[index++] = tmp_dataAddr.byte.high;
        g_UartDispTxBuf[index++] = tmp_dataAddr.byte.low;
        g_UartDispTxBuf[index++] = 1;

        tmp_dataWord.word = g_UserSet.PrjSetValue;
        g_UartDispTxBuf[index++] = tmp_dataWord.byte.high;
        g_UartDispTxBuf[index++] = tmp_dataWord.byte.low;
    }else{
        switch (s_comm_tx_step)
        {
            case 0:            
                if(g_DispCommHasInitBit & 0x01){
                    s_comm_tx_step = 1;
                    return;
                }
                g_UartDispTxBuf[index++] = 0x03;
                tmp_dataAddr.word = 0;
                g_UartDispTxBuf[index++] = tmp_dataAddr.byte.high;
                g_UartDispTxBuf[index++] = tmp_dataAddr.byte.low;
                g_UartDispTxBuf[index++] = 21;
                s_comm_tx_step = 1;
                s_tx_count = 0;
                break;

            case 1:
                if((g_DispCommHasInitBit & 0x01) == 0){
                    s_comm_tx_step = 0;
                    s_tx_count = 0;
                    return;
                }else if(g_DispCommHasInitBit & 0x02){
                    s_comm_tx_step = 2;
                    s_tx_count = 0;
                    return;
                }
                g_UartDispTxBuf[index++] = 0x03;
                tmp_dataAddr.word = 100 + s_tx_count*32;
                g_UartDispTxBuf[index++] = tmp_dataAddr.byte.high;
                g_UartDispTxBuf[index++] = tmp_dataAddr.byte.low;
                reg_count = (module_word_reg[18] >= 100) ? 100 : module_word_reg[18];
                g_UartDispTxBuf[index++] = ((reg_count - s_tx_count*32) > 32)?32:(reg_count - s_tx_count*32);
                if(s_tx_count < ((reg_count - 1) / 32)){
                    s_tx_count++;
                }else{
                    s_tx_count = 0;
                }
                break;

            case 2:
                if((g_DispCommHasInitBit & 0x02) == 0){
                    s_comm_tx_step = 0;
                    s_tx_count = 0;
                    return;
                }else if(g_DispCommHasInitBit & 0x04){
                    s_comm_tx_step = 3;
                    s_tx_count = 0;
                    return;
                }

                g_UartDispTxBuf[index++] = 0x03;
                tmp_dataAddr.word = 200 + s_tx_count*32;
                g_UartDispTxBuf[index++] = tmp_dataAddr.byte.high;
                g_UartDispTxBuf[index++] = tmp_dataAddr.byte.low;
                reg_count = (module_word_reg[18] >= 100) ? 100 : module_word_reg[18];
                g_UartDispTxBuf[index++] = ((reg_count - s_tx_count*32) > 32)?32:(reg_count - s_tx_count*32);
                if(s_tx_count < ((reg_count - 1) / 32)){
                    s_tx_count++;
                }else{
                    s_tx_count = 0;
                }
                break;

            case 3:
                if((g_DispCommHasInitBit & 0x07) != 7){
                    s_comm_tx_step = 0;
                    s_tx_count = 0;
                    return;
                }
                g_UartDispTxBuf[index++] = 0x03;
                tmp_dataAddr.word = 600;
                g_UartDispTxBuf[index++] = tmp_dataAddr.byte.high;
                g_UartDispTxBuf[index++] = tmp_dataAddr.byte.low;
                g_UartDispTxBuf[index++] = 23;
                s_comm_tx_step = 4;
                s_tx_count = 0;
                break;

            case 4:
                if((g_DispCommHasInitBit & 0x07) != 7){
                    s_comm_tx_step = 0;
                    return;
                }
                g_UartDispTxBuf[index++] = 0x03;
                tmp_dataAddr.word = 400 + s_tx_count*32;
                g_UartDispTxBuf[index++] = tmp_dataAddr.byte.high;
                g_UartDispTxBuf[index++] = tmp_dataAddr.byte.low;
                g_UartDispTxBuf[index++] = ((module_word_reg[19] - s_tx_count*32) > 32)?32:(module_word_reg[19] - s_tx_count*32);
                if(s_tx_count < ((module_word_reg[19] - 1) / 32)){
                    s_tx_count++;
                }else{
                    s_tx_count = 0;
                    s_comm_tx_step = 5;
                }
                break;

            case 5:
                if((g_DispCommHasInitBit & 0x07) != 7){
                    s_comm_tx_step = 0;
                    return;
                }
                g_UartDispTxBuf[index++] = 0x03;
                tmp_dataAddr.word = 800 + s_tx_count*32;
                g_UartDispTxBuf[index++] = tmp_dataAddr.byte.high;
                g_UartDispTxBuf[index++] = tmp_dataAddr.byte.low;
                g_UartDispTxBuf[index++] = ((module_word_reg[18] - s_tx_count*32) > 32)?32:(module_word_reg[18] - s_tx_count*32);
                if(s_tx_count < ((module_word_reg[18] - 1) / 32)){
                    s_tx_count++;
                }else{
                    s_tx_count = 0;
                    s_comm_tx_step = 6;
                }
                break;

            case 6:
                if((g_DispCommHasInitBit & 0x07) != 7){
                    s_comm_tx_step = 0;
                    return;
                }
                g_UartDispTxBuf[index++] = 0x03;
                tmp_dataAddr.word = 1000 + s_tx_count*32;
                g_UartDispTxBuf[index++] = tmp_dataAddr.byte.high;
                g_UartDispTxBuf[index++] = tmp_dataAddr.byte.low;
                g_UartDispTxBuf[index++] = ((module_word_reg[20] - s_tx_count*32) > 32)?32:(module_word_reg[20] - s_tx_count*32);
                if(s_tx_count < ((module_word_reg[20] - 1) / 32)){
                    s_tx_count++;
                }else{
                    s_tx_count = 0;
                    s_comm_tx_step = g_UserSet.Updata2CommCnt ? 7 : 3;
                }
                break;

            case 7:
                if(g_UserSet.Updata2CommCnt){
                    g_UserSet.Updata2CommCnt--;
                }else{
                    s_tx_count = 0;
                    s_comm_tx_step = 3;
                    return;
                }
                if((g_DispCommHasInitBit & 0x07) != 7){
                    s_comm_tx_step = 0;
                    return;
                }
                g_UartDispTxBuf[index++] = 0x10;
                tmp_dataAddr.word = 600;
                g_UartDispTxBuf[index++] = tmp_dataAddr.byte.high;
                g_UartDispTxBuf[index++] = tmp_dataAddr.byte.low;
                g_UartDispTxBuf[index++] = 6;

                tmp_BitWord.word = (g_UserSet.Mode & 0x0F); 
                tmp_BitWord.bit.b4 = g_UserSet.f_On  ? 1 : 0;
                tmp_dataWord.word = tmp_BitWord.word;

                g_UartDispTxBuf[index++] = tmp_dataWord.byte.high;      //模式+开关机
                g_UartDispTxBuf[index++] = tmp_dataWord.byte.low;       //模式+开关机
                
                g_UartDispTxBuf[index++] = (g_UserSet.SetTemp[USER_SET_MODE_WATER] >> 8) & 0xFF;  //ZONE2制热设定温度
                g_UartDispTxBuf[index++] = (g_UserSet.SetTemp[USER_SET_MODE_WATER] >> 0) & 0xFF;  //ZONE2制热设定温度

                s_tx_count = 0;
                s_comm_tx_step = 3;
                break;
            
            default:
                break;
        }
    }
    s_Second = g_CurrentRTC.Second;

    tmp_crc16.word = crc16(&(g_UartDispTxBuf[0]), index);
    g_UartDispTxBuf[index++] = tmp_crc16.byte.high;
    g_UartDispTxBuf[index++] = tmp_crc16.byte.low;

    uart_write_bytes(1, g_UartDispTxBuf, index);
}

void *thread_uart_tx(void *arg)
{
    int value = 0;
    while (1){
        if(parse_sem_pend(&rs485_sem, 2000) <= 0){
            printf("parse_sem_pend timeout! ...\r\n");
        }else{
            printf("parse_sem_pend ok! ...\r\n");
        }
        if(g_UserSet.UpgradeTimer) {
            continue;
        }
        sleep_ms(15);
        fun_CommDispTx();
        mach_rx_buff_length = 0;
    }
}

int vdata_parse_93_frame(uint8_t *data, uint16_t datalength)
{
    static uint8_t buff_wifi[50];
    uint16_t check_sum = 0;
    if(data[0] == 0x5A){
        check_sum = crc16(&data[1], datalength - 3);
        if(check_sum == (((uint16_t)data[datalength - 2] << 8) + (uint16_t)data[datalength - 1])){
            if(g_UserSet.UpgradeTimer){
                g_UserSet.UpgradeTimeout = 29;
                buff_wifi[0] = 0;//DAH
                buff_wifi[1] = 0;//DAL
                buff_wifi[2] = data[3];//CMD
                buff_wifi[3] = data[5];//回复收到的ROM数据包序号（从0开始）
                buff_wifi[4] = data[6];//回复收到的ROM数据包序号（从0开始）
                buff_wifi[5] = data[7] ? data[7] : 1; // 错误代码
                buff_wifi[6] = data[8];//错误代码
                mcu_dp_raw_update(DPID_OTA_WRDAT, buff_wifi, 7);
            }
            return 1;
        }
    }
    return 0;
}


void *thread_uart_rs485(void *argc)
{
    uint8_t buff[5*1024];
    int rs485_rev_len = 0, len = 0, status = 0;

    fd_rs485 = open(RS485_1, O_RDWR | O_NOCTTY, 0);
    if (fd_rs485 < 0) {
        printf("open %s error %s\n", RS485_1, strerror(errno));
        return (void*)1;
    }
    printf("open %s success \r\n", RS485_1);
    if (setup_port(fd_rs485, 9600, 8, 0, 1)) {
        printf("setup_port error %s\n", strerror(errno));
        close(fd_rs485);
        return (void*)1;
    }
    printf("setup_port %s success \r\n", RS485_1);

    pthread_detach(pthread_self());
    while(1){
        len = read_data(fd_rs485, &buff[rs485_rev_len], 1024);
        if (len > 0) {
            if(protocol_stack_parse(1, buff, len) > 0){
                parse_sem_post(&rs485_sem, (void *)&len);
                // xQueueSend(comm_queue, (void *)&value, 0);
            }else{
                vdata_parse_93_frame(rs485_buff, len);
            }
            // printf("recv1 data [%d]...\r\n", len);
        }else{
            sleep_ms(1);
        }
    }
}

void *thread_uart_tuya(void *argc)
{
    uint8_t buff[5*1024];
    int len = 0;

    fd_tuya = open("/dev/ttyS3", O_RDWR, 0);
    if (fd_tuya < 0) {
        printf("open %s error %s\n", "/dev/ttyS3", strerror(errno));
        return (void*)1;
    }
    printf("open %s success \r\n", "/dev/ttyS3");
    if (setup_port(fd_tuya, 115200, 8, 0, 1)) {
        printf("setup_port error %s\n", strerror(errno));
        close(fd_tuya);
        return (void*)1;
    }
    printf("setup_port %s success \r\n", "/dev/ttyS3");

    wifi_protocol_init();
    pthread_detach(pthread_self());
    while(1){
        len = read_data(fd_tuya, &buff[0], 1024);
        if (len > 0) {
            uart_receive_buff_input(buff, len);
            printf("recv2 data [%d]...\r\n", len);
        }else{
            sleep_ms(1);
        }
        wifi_uart_service();
    }
}

void rs485_start(void)
{
    int j = 0;
    int res = 0;
    pthread_t tid_uart_rs485, tid_uart_tuya, tid_uart_tx;

    // for (j = 0; j < REG_MAX_NUM; j++){
    //     module_word_reg[j] = j;
    // }
    
    system("echo 200 > /sys/class/gpio/export");
    system("echo out > /sys/class/gpio/gpio200/direction");
    system("echo 1 > /sys/class/gpio/gpio200/value");

    res = pthread_create(&tid_uart_tuya , NULL , thread_uart_tuya , NULL);
    if(res){
        perror("thread_uart_tuya creat error!\r\n");
    }
    res = pthread_create(&tid_uart_rs485 , NULL , thread_uart_rs485 , NULL);
    if(res){
        perror("thread_uart_rs485 creat error!\r\n");
    }
    res = pthread_create(&tid_uart_tx , NULL , thread_uart_tx , NULL);
    if(res){
        perror("thread_uart_tx creat error!\r\n");
    }


    // xTaskCreate(task_wifi_comm, "task_wifi_comm", 4096, NULL, 12, NULL);
    // xTaskCreate(task_rs485_comm, "task_rs485_comm", 4096, NULL, 12, NULL);
    // xTaskCreate(task_mach_comm, "task_mach_comm", 4096, NULL, 20, NULL);
}
